﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;

namespace G.Controls
{
    [TemplatePart(Name = "PART_AnimationElementContainer", Type = typeof(Canvas)), TemplatePart(Name = "PART_AnimationElement", Type = typeof(FrameworkElement))]
    public class LoadingIndicator : Control
    {
        public static readonly DependencyProperty IsAnimationProperty = DependencyProperty.Register("IsAnimation", typeof(bool), typeof(LoadingIndicator), new PropertyMetadata(true, LoadingIndicator.IsAnimationChanged));

        public static readonly DependencyProperty AnimationElementTemplateProperty = DependencyProperty.Register("AnimationElementTemplate", typeof(DataTemplate), typeof(LoadingIndicator), new PropertyMetadata(null));
        private static readonly DependencyProperty ControlVisibilityProperty = DependencyProperty.Register("ControlVisibility", typeof(Visibility), typeof(LoadingIndicator), new PropertyMetadata(Visibility.Visible, new PropertyChangedCallback(LoadingIndicator.OnControlVisibilityPropertyChanged)));
        /// <summary>
        /// 花瓣数目
        /// </summary>
        public static readonly DependencyProperty CountProperty = DependencyProperty.Register("Count", typeof(int), typeof(LoadingIndicator), new PropertyMetadata(12, new PropertyChangedCallback(LoadingIndicator.OnCountPropertyChanged)));
        private const int DefaultCount = 12;
        private const double DefaultDurationInSeconds = 1.0;
        public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(LoadingIndicator), new PropertyMetadata(TimeSpan.FromSeconds(1.0), new PropertyChangedCallback(LoadingIndicator.OnDurationPropertyChanged)));
        private const double EndOpacity = 0.1;
        private const string PART_AnimationElement = "PART_AnimationElement";
        private const string PART_AnimationElementContainer = "PART_AnimationElementContainer";

        public LoadingIndicator()
        {
            base.DefaultStyleKey = typeof(LoadingIndicator);
            storyboard = new Storyboard();
        }
        Storyboard storyboard;
        private void CreateAnimation()
        {
            if (this.animationElementContainer != null)
            {
                storyboard.Stop();
                storyboard.Children.Clear();
                this.animationElementContainer.Children.Clear();
                double num = 360.0 / ((double)this.Count);
                double width = this.animationElement.Width;
                double num3 = (base.Width - width) / 2.0;
                double num4 = base.Height / 2.0 + this.innerRadius;

                for (int i = 0; i < this.Count; i++)
                {
                    FrameworkElement element = this.AnimationElementTemplate.LoadContent() as FrameworkElement;
                    element.Opacity = 0.0;
                    TranslateTransform transform3 = new TranslateTransform
                    {
                        X = num3,
                        Y = num4
                    };
                    TranslateTransform transform = transform3;
                    RotateTransform transform4 = new RotateTransform
                    {
                        Angle = i * num + 180.0,
                        CenterX = width / 2.0,
                        CenterY = -this.innerRadius
                    };
                    RotateTransform transform2 = transform4;
                    TransformGroup group = new TransformGroup
                    {
                        Children = { transform2, transform }
                    };
                    element.RenderTransform = group;
                    this.animationElementContainer.Children.Add(element);
                    DoubleAnimation animation2 = new DoubleAnimation
                    {
                        From = new double?(this.animationElement.Opacity),
                        To = 0.1,
                        Duration = this.Duration,
                        RepeatBehavior = RepeatBehavior.Forever,
                        BeginTime = new TimeSpan?(TimeSpan.FromMilliseconds(this.Duration.TotalMilliseconds / ((double)this.Count) * i))
                    };
                    DoubleAnimation animation = animation2;
                    Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity", new object[0]));
                    Storyboard.SetTarget(animation, element);
                    storyboard.Children.Add(animation);
                }
                storyboard.Begin();
                Binding binding = new Binding
                {
                    Source = this,
                    Path = new PropertyPath("Visibility", new object[0])
                };
                base.SetBinding(ControlVisibilityProperty, binding);
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.animationElementContainer = base.GetTemplateChild("PART_AnimationElementContainer") as Canvas;
            if (this.animationElementContainer == null) throw new NotImplementedException("Template PART_AnimationElementContainer is required to display LoadingIndicator.");
            this.animationElement = this.AnimationElementTemplate.LoadContent() as FrameworkElement;
            if (this.animationElement == null) throw new NotImplementedException("AnimationElementTemplate is required to display LoadingIndicator.");
            double num = Math.Min(base.Width, base.Height);
            this.innerRadius = num / 2.0 - Math.Max(this.animationElement.Width, this.animationElement.Height);
            this.CreateAnimation();
            if (!IsAnimation)
                this.storyboard.Stop();
        }

        private static void OnControlVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadingIndicator indicator = d as LoadingIndicator;
            Visibility newValue = (Visibility)e.NewValue;
            if (indicator.animationElementContainer != null)
            {
                if (newValue == Visibility.Collapsed)
                    indicator.StopAnimation();
                else
                    indicator.StartAnimation();
            }
        }

        private static void OnCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadingIndicator indicator = d as LoadingIndicator;
            if ((int)e.NewValue <= 0) indicator.Count = 12;
            indicator.CreateAnimation();
        }

        private static void OnDurationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as LoadingIndicator).CreateAnimation();
        }

        public bool IsAnimation
        {
            get { return (bool)this.GetValue(LoadingIndicator.IsAnimationProperty); }
            set { this.SetValue(LoadingIndicator.IsAnimationProperty, value); }
        }
        private static void IsAnimationChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            LoadingIndicator l = obj as LoadingIndicator;
            if (l.IsAnimation)
            {
                if (l.storyboard.Children.Count == 0)
                    l.CreateAnimation();
                else
                {
                    l.storyboard.Begin();
                }

            }
            else
            {
                l.storyboard.Stop();
            }
        }
        public void StartAnimation()
        {
            this.IsAnimation = true;
        }

        public void StopAnimation()
        {
            this.IsAnimation = false;
        }

        private FrameworkElement animationElement { get; set; }

        private Canvas animationElementContainer { get; set; }

        public DataTemplate AnimationElementTemplate
        {
            get
            {
                return (DataTemplate)base.GetValue(AnimationElementTemplateProperty);
            }
            set
            {
                base.SetValue(AnimationElementTemplateProperty, value);
            }
        }

        private Visibility ControlVisibility
        {
            get
            {
                return (Visibility)base.GetValue(ControlVisibilityProperty);
            }
            set
            {
                base.SetValue(ControlVisibilityProperty, value);
            }
        }

        public int Count
        {
            get
            {
                return (int)base.GetValue(CountProperty);
            }
            set
            {
                base.SetValue(CountProperty, value);
            }
        }

        public TimeSpan Duration
        {
            get
            {
                return (TimeSpan)base.GetValue(DurationProperty);
            }
            set
            {
                base.SetValue(DurationProperty, value);
            }
        }

        private double innerRadius { get; set; }

        //private List<Storyboard> storyboardList { get; set; }
    }
}
